package com.io.aspect;

import com.alibaba.fastjson.JSON;
import com.io.annotation.MyLog;
import com.io.entity.SysLog;
import com.io.security.security.TokenManager;
import com.io.service.SysLogService;
import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * aop切面，记录日志
 *
 * @author hexp
 */
@Aspect
@Component
public class SysLogAspect {

    private static Logger logger = LoggerFactory.getLogger(SysLogAspect.class);


    @Autowired
    private SysLogService sysLogService;


    private TokenManager tokenManager;


    @Autowired
    SysLogAspect(TokenManager tokenManager) {
        this.tokenManager = tokenManager;
    }


    /**
     * 配置切入点（配置为自定义注解）
     */
    @Pointcut("@annotation(com.io.annotation.MyLog)")
    public void logPointCut() {
    }

    /**
     * 环绕通知
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 开始时间
        long startTime = System.currentTimeMillis();
        //执行方法
        Object proceed = joinPoint.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - startTime;

        // 保存日志
        try {
            saveLog(joinPoint, time);

        } catch (Exception e) {
            logger.error("【记录日志】，{}", e);
        }

        return proceed;
    }

    /**
     * 日志入库
     *
     * @param joinPoint
     * @param time
     */
    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取控制器，包含报包名
        String className = joinPoint.getTarget().getClass().getName();
        // 获取方法名
        String methodName = signature.getName();
        // 获取参数
        Object[] args = joinPoint.getArgs();

        // 打印该方法耗时时间
        logger.info("请求{}.{}耗时{}毫秒", className, methodName, time);

        SysLog sysLog = new SysLog();
        sysLog.setMethod(className + "." + methodName);
        try {// 可能会出现转换错误
            sysLog.setParams(args.length != 0 ? JSON.toJSONString(args) : "");
        } catch (Exception e) {
        }
        // 获取自定义注解的字段值
        MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
        if (myLog != null) {
            // 注解上的描述
            sysLog.setOperation(myLog.title() + "-" + myLog.action());
        }
        // 获取 ip
        String ip = request.getRemoteAddr();
        sysLog.setIp(ip);

        // 请求类型
        String method = request.getMethod();
        if (method!=null){
            sysLog.setParams(method);
        }
        //执行时间
        sysLog.setTime(time);
        //方法名
        sysLog.setMethod(methodName);

        //用户名
        String token = request.getHeader("token");
        if (token != null) {
            //从token获取用户名
            String username = tokenManager.getUserInfoFromToken(token);
            sysLog.setUsername(username);
            sysLogService.save(sysLog);
        }
    }
}